/********************************************************************************
 * Project Name		[JavaSE_Fundamentals]
 * File Name     	[AnnotationEngine.java]
 * Creation Date 	[2015-01-01]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ********************************************************************************/
package jdk5.annotation.cases;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jdk5.annotation.cases.annotation.WebInitParam;
import jdk5.annotation.cases.annotation.WebServlet;
import jdk5.annotation.cases.utils.ClassScannerUtils;

/**
 * 负责处理注解, 使用过滤器实现, 要引入JavaEE相关包<br/>
 * 
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 * 
 */
public class AnnotationEngine implements Filter {

	private ServletContext servletContext;

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		servletContext = filterConfig.getServletContext();

		// 扫描web.xml中配置的Servlet包
		Map<String, Class<?>> classMap = new HashMap<>();
		String servletPackageName = filterConfig.getInitParameter("servletPackage");
		if (servletPackageName.indexOf(',') != -1) {
			String[] packageNames = servletPackageName.split(",");
			for (String packageName : packageNames) {
				try {
					this.loadServletClassToContext(packageName, classMap);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		} else {
			try {
				this.loadServletClassToContext(servletPackageName, classMap);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	private void loadServletClassToContext(String packageName, Map<String, Class<?>> classMap) throws Exception {
		Set<Class<?>> classes = ClassScannerUtils.getClasses(packageName);
		for (Class<?> classType : classes) {
			// 如果该类有WebServlet注解
			if (classType.isAnnotationPresent(WebServlet.class)) {
				WebServlet webServlet = classType.getAnnotation(WebServlet.class);
				String mappingURLValue = webServlet.value();
				// 如果注解实例webServlet的value属性不为空
				if (!"".equals(mappingURLValue)) {
					classMap.put(mappingURLValue, classType);
				}

				// 如果注解实例webServlet的urlPatterns属性不为空
				String[] urlPatterns = webServlet.urlParttens();
				if (urlPatterns != null && urlPatterns.length > 0) {
					for (String url : urlPatterns) {
						classMap.put(url, classType);
					}
				}

				servletContext.setAttribute("servletClassMap", classMap);
			}
		}
	}

	@SuppressWarnings("unchecked")
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {

		HttpServletRequest httpRequest = (HttpServletRequest) request;
		HttpServletResponse httpResponse = (HttpServletResponse) response;

		Map<String, Class<?>> classMap = (Map<String, Class<?>>) servletContext.getAttribute("servletClassMap");

		// 获得ContextPath
		String contextPath = httpRequest.getContextPath();
		// 获得请求的URI
		String uri = httpRequest.getRequestURI();

		// 获取用户的请求方式
		String method = httpRequest.getMethod();
		// 获得请求的Servlet路径
		String servletPath = uri.substring(contextPath.length(), uri.lastIndexOf('.'));
		// 从classMap中找到对应uri的servlet类[使用了WebServlet注解的类]
		Class<?> classType = classMap.get(servletPath);

		try {
			Object object = classType.newInstance();

			// 得到doGet()或doPost()方法
			Method invokeMethod = classType.getDeclaredMethod(
					"do" + method.substring(0, 1) + method.substring(1).toLowerCase(), HttpServletRequest.class,
					HttpServletResponse.class);

			// 得到初始化参数
			WebServlet webServlet = classType.getAnnotation(WebServlet.class);
			WebInitParam[] initParams = webServlet.initParams();
			for (WebInitParam webInitParam : initParams) {
				System.out.println(
						"param name = " + webInitParam.paramName() + " param value = " + webInitParam.paramValue());
			}

			invokeMethod.invoke(object, httpRequest, httpResponse);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void destroy() {
	}
}
